<!--
  input公共组件                 zls-2022/06/02
      Attributes
          1、value              输入框的值（默认为''）
          2、type               文本框 / 密码框 / 富文本 （默认为文本框）
          3、placeholder        提示内容（默认为 '请输入'）
          4、maxlength          可输入最大长度（默认为100）
          5、readonly           是否只读（默认为false）
          6、label              左侧内容
          7、labelWidth         左侧内容的宽度（默认78）
          8、unit               右侧内容（默认为''）
          9、svg                右侧图标（默认为''，需要添加向右箭头的：jiantou）
          10、clearable         是否显示清空图标（默认为true）
          11、showPassword      是否显示切换密码图标（默认为false）
          12、clickable         是否开启点击反馈（默认为false）
          13、autosize          是否开启textarea的高度自适应，也就是不会出现滚动条（默认为true）
          14、clickSvg          是否开启右侧图标的点击事件（默认为false）

      Events
          1、input              输入框内容变化时触发
          2、blur               输入框失去焦点时触发
          3、focus              输入框获得焦点时触发
          4、click              点击整行时触发
          5、click-svg          点击右侧图标时触发

      Demo==>
          参考 Form 表单组件
-->
<template>
  <div class="z-input" :class="{ 'z-input-clickable': clickable }" @click.stop="clickRow">
    <div class="z-input-label" :style="{ width: pxToRem(labelWidth) }">
      <span class="z-input-label-required">{{ formItem.isRequired ? '*' : '' }}</span>
      <span class="z-input-label-title">{{ label }}</span>
    </div>
    <div class="z-input-content">
      <textarea
        v-if="type === 'textarea'"
        id="textarea"
        rows="3"
        :value="modelValue"
        :placeholder="placeholder"
        :maxlength="maxlength"
        :readonly="readonly"
        @blur="blur"
        @focus="focus"
        @input="input"
      ></textarea>
      <input
        v-else
        :type="showPassword ? (passwordVisible ? 'text' : 'password') : type"
        :value="modelValue"
        :placeholder="placeholder"
        :maxlength="maxlength"
        :readonly="readonly"
        @blur="blur"
        @focus="focus"
        @input="input"
      />
      <div class="z-input-content-tips" v-if="formItem.validateState">{{ formItem.validateMessage }}</div>
    </div>
    <div class="z-input-right">
      <!-- 关闭按钮 -->
      <div class="z-input-right-close" v-if="clearable && modelValue" @click.stop="clear"></div>
      <!-- 切换密码显示与隐藏 -->
      <z-svg class="showPassword" v-if="type === 'password' && showPassword" :name="passwordVisible ? 'yanjing' : 'yanjing1'" @click="passwordVisible = !passwordVisible"></z-svg>
      <!-- 单位 -->
      <span class="z-input-right-unit" v-if="unit">{{ unit }}</span>
      <!-- 图标 -->
      <z-svg class="right-svg" v-if="svg" :name="svg" @click.stop="clickRightSvg"></z-svg>
    </div>
  </div>
</template>

<script>
export default { name: 'z-input' }
</script>
<script setup>
import { ref, onMounted, inject, getCurrentInstance } from 'vue'
import { pxToRem } from '@/utils/index'
const global = getCurrentInstance().appContext.config.globalProperties
const emit = defineEmits(['update:modelValue', 'click', 'click-svg', 'blur', 'focus', 'input'])
const props = defineProps({
  // 输入框的值（默认为''）
  modelValue: {
    type: [Number, String, Array],
    default: ''
  },
  // 文本框 / 密码框 / 富文本 （默认为文本框）
  type: {
    type: String,
    default: 'text'
  },
  // 提示内容（默认为 '请输入'）
  placeholder: {
    type: String,
    default: '请输入'
  },
  // 可输入最大长度（默认为100）
  maxlength: {
    type: Number,
    default: 100
  },
  // 是否只读（默认为false）
  readonly: {
    type: Boolean,
    default: false
  },
  // 左侧内容
  label: {
    type: String,
    default: ''
  },
  // 左侧内容的宽度（默认78）
  labelWidth: {
    type: Number,
    default: 78
  },
  // 右侧内容（默认为''）
  unit: {
    type: String,
    default: ''
  },
  // 右侧图标（默认为''，需要添加向右箭头的：jiantou）
  svg: {
    type: String,
    default: ''
  },
  // 是否显示清空图标（默认为true）
  clearable: {
    type: Boolean,
    default: true
  },
  // 是否显示切换密码图标（默认为false）
  showPassword: {
    type: Boolean,
    default: false
  },
  // 是否开启点击反馈（默认为false）
  clickable: {
    type: Boolean,
    default: false
  },
  // 是否开启textarea的高度自适应，也就是不会出现滚动条（默认为true）
  autosize: {
    type: Boolean,
    default: true
  },
  // 是否开启右侧图标的点击事件（默认为false）
  clickSvg: {
    type: Boolean,
    default: false
  }
})

const passwordVisible = ref(false) // 切换密码图标
const formItem = inject('formItem')

onMounted(() => {
  props.autosize && props.type === 'textarea' && autoTextarea()
})

// 点击整行触发
function clickRow() {
  if (!props.clickable || !props.readonly) return
  emit('click')
}

// 点击右侧图标
function clickRightSvg() {
  if (!props.clickSvg || props.readonly) return
  emit('click-svg')
}

// 失去焦点
function blur(e) {
  emit('blur', e.target.value)
  global.$bus.emit('formItem-blur', formItem.value.prop || 'noProp')
}

// 获取焦点
function focus(e) {
  emit('focus', e.target.value)
}

// 实时改变
function input(e) {
  emit('update:modelValue', e.target.value)
  emit('input', e.target.value)
  global.$bus.emit('formItem-change', formItem.value.prop || 'noProp')
}

// 点击清空图标
function clear() {
  emit('update:modelValue', '')
  emit('input', '')
  props.clickable && props.readonly ? global.$bus.emit('formItem-change', formItem.value.prop || 'noProp') : global.$bus.emit('formItem-blur', formItem.value.prop || 'noProp')
}

// textarea自适应高度
function autoTextarea(extra = 0, maxHeight = 0) {
  let elem = document.getElementById('textarea')
  let isFirefox = !!document.getBoxObjectFor || 'mozInnerScreenX' in window,
    isOpera = !!window.opera && !!window.opera.toString().indexOf('Opera'),
    addEvent = function (type, callback) {
      elem.addEventListener ? elem.addEventListener(type, callback, false) : elem.attachEvent('on' + type, callback)
    },
    getStyle = elem.currentStyle
      ? function (name) {
          let val = elem.currentStyle[name]
          if (name === 'height' && val.search(/px/i) !== 1) {
            let rect = elem.getBoundingClientRect()
            return rect.bottom - rect.top - parseFloat(getStyle('paddingTop')) - parseFloat(getStyle('paddingBottom')) + 'px'
          }
          return val
        }
      : function (name) {
          return getComputedStyle(elem, null)[name]
        },
    minHeight = parseFloat(getStyle('height'))
  elem.style.resize = 'none'

  const change = function () {
    let scrollTop,
      height,
      padding = 0,
      style = elem.style
    if (elem._length === elem.value.length) return
    elem._length = elem.value.length
    if (!isFirefox && !isOpera) {
      padding = parseInt(getStyle('paddingTop')) + parseInt(getStyle('paddingBottom'))
    }
    scrollTop = document.body.scrollTop || document.documentElement.scrollTop
    elem.style.height = minHeight + 'px'
    if (elem.scrollHeight > minHeight) {
      if (maxHeight && elem.scrollHeight > maxHeight) {
        height = maxHeight - padding
        style.overflowY = 'auto'
      } else {
        height = elem.scrollHeight - padding
        style.overflowY = 'hidden'
      }
      style.height = height + extra + 'px'
      scrollTop += parseInt(style.height) - elem.currHeight
      document.body.scrollTop = scrollTop
      document.documentElement.scrollTop = scrollTop
      elem.currHeight = parseInt(style.height)
    }
  }
  addEvent('propertychange', change)
  addEvent('input', change)
  addEvent('focus', change)
  change()
}
</script>

<style scoped lang="scss">
$warnColor: #ee0a24;
.z-input {
  display: flex;
  padding: 10px 0;
  line-height: 20px;
  border-bottom: 1px solid $border;
  font-size: 14px;
  &.z-input-clickable:active {
    background-color: $border;
  }
  &-label {
    margin-right: 6px;
    display: flex;
    &-required {
      color: $warnColor;
      width: 6px;
    }
  }
  &-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    > input,
    > textarea {
      width: 100%;
      background-color: transparent;
      border: 0;
      resize: none;
    }
    ::placeholder {
      color: #ccc;
    }
    &-tips {
      font-size: 12px;
      color: $warnColor;
      padding-left: 2px;
    }
  }
  &-right {
    display: flex;
    &-close {
      width: 15px;
      height: 15px;
      border-radius: 15px;
      background-color: #c8c9cc;
      position: relative;
      top: 3px;
      margin-left: 6px;
      &::before,
      &::after {
        content: '';
        position: absolute;
        height: 7px;
        width: 1px;
        top: 4px;
        left: 7px;
        background-color: #fff;
      }
      &::before {
        transform: rotate(45deg);
      }
      &::after {
        transform: rotate(-45deg);
      }
    }
    &-unit {
      margin-left: 6px;
    }
    > svg.right-svg {
      font-size: 20px;
      position: relative;
      right: -5px;
    }
    > svg.showPassword {
      font-size: 16px;
      position: relative;
      top: 3px;
      margin-left: 6px;
    }
  }
}
</style>
